import cv2
import sys
import os
import time
import queue
import numpy as np
import multiprocessing
from data_adjust.threshold_adjust import *
from driver.hdmi_show import *

RUNNING_FLAG = multiprocessing.Event() # 所有任务运行标志
RUNNING_FLAG.set()  # 设置为True，表示所有任务正在运行

ENABLE_FRAME_1 = multiprocessing.Value('b',  True)      # 主摄像头显示 :  True开启  False关闭
ENABLE_TOUCH_SCREEN = multiprocessing.Value('i', 1)    # 触摸屏控制:  True: 启用, False: 禁用

frame1_queue = multiprocessing.Queue(maxsize=5) #  创建一个队列用于从摄像头进程接收帧
touch_data_queue = multiprocessing.Queue(maxsize=5) # 用于发送触摸数据

def restart_program():
    python = sys.executable      # Python 解释器路径
    os.execl(python, python, *sys.argv)  # 替换当前进程，重新执行

# --- UI 绘制相关的配置 (主进程使用) ---
# 除了 TOUCH_SCREENS 定义的触摸区域，我们还需要定义如何绘制这些元素和滑条
# 这里定义滑条的绘制样式
SLIDER_DRAW_CONFIG = {
    'line_color': (150, 150, 150), # 滑条轨道颜色
    'line_thickness': 4,          # 滑条轨道粗细
    'slider_bar_color': (0, 0, 255), # 滑块颜色 (红色)
    'slider_bar_width': 8,        # 滑块宽度 (垂直线)
    'slider_bar_height_offset': 5, # 滑块高度相对于区域的高度偏移 (使滑块略高于轨道)
    'label_offset_x': +5,          # 滑条标签文字相对于区域顶部的偏移
    'label_offset_y': -5,          # 滑条标签文字相对于区域顶部的偏移
    'font_scale': 0.6,             # 标签字体大小比例
    'font_thickness': 2,           # 标签字体粗细
    'text_color': (0, 200, 200), # 标签文字颜色 
}

# 按钮绘制样式
BUTTON_DRAW_CONFIG = {
    'default_color': (50, 50, 150), # 默认颜色 (暗紫色)
    'selected_color': (100, 100, 200), # 选中颜色 (亮紫色)
    'save_color': (0, 150, 0),       # 保存按钮颜色 (绿色)
    'save_disabled_color': (50, 80, 50), # 保存按钮禁用颜色 (暗绿色)
    'font_scale': 1,                 # 标签字体大小比例
    'font_thickness': 2,           # 标签字体粗细
    'text_color': (0, 200, 200), # 标签文字颜色 
}

# --- 参数管理和状态 ---
current_mode = None # 当前模式 ('hsv', 'binary', None)
current_color = None
current_params = {} # 当前模式的参数 {key: value}
saved_configs = []  # 存储保存的配置
CONFIGS_FILE = '/home/sunrise/cricket-training-questions/model/thresholds.json' # 配置文件路径
DEFAULT_CONFIGS = []  # 默认就是空列表
# 加载已保存的配置
def load_configs():
    global saved_configs

    # 文件不存在或大小为 0 → 初始化
    if not os.path.exists(CONFIGS_FILE) or os.path.getsize(CONFIGS_FILE) == 0:
        saved_configs = DEFAULT_CONFIGS.copy()
        # 确保目录存在
        os.makedirs(os.path.dirname(CONFIGS_FILE), exist_ok=True)
        with open(CONFIGS_FILE, 'w') as f:
            json.dump(saved_configs, f, indent=2)
        print(f"[Main Process] 配置文件不存在或为空，已创建：{CONFIGS_FILE}")
        return

    # 文件存在且非空 → 尝试加载
    try:
        with open(CONFIGS_FILE, 'r') as f:
            saved_configs = json.load(f)
        # 可选：校验 loaded 类型
        if not isinstance(saved_configs, list):
            raise ValueError(f"期望 list，但拿到 {type(saved_configs).__name__}")
        print(f"[Main Process] 成功加载 {len(saved_configs)} 条配置。")

    except (json.JSONDecodeError, ValueError) as e:
        # 解析出错 → 备份并重置
        backup_path = CONFIGS_FILE + '.bak'
        os.replace(CONFIGS_FILE, backup_path)
        saved_configs = DEFAULT_CONFIGS.copy()
        with open(CONFIGS_FILE, 'w') as f:
            json.dump(saved_configs, f, indent=2)
        print(f"[Main Process] 加载配置失败：{e}")
        print(f"[Main Process] 已备份原文件到 {backup_path}，并重置为空列表。")

# 保存当前配置
def save_current_config():

    global current_mode,current_color,current_params, saved_configs

    if not current_mode:
        print("[Main Process] No active mode configuration to save.")
        return
    print(f"[Main Process] Saving current configuration: {current_mode}, {current_color}, {current_params}")

    # 新的配置项
    config_to_save = {
        'mode': current_mode,
        'color': current_color,
        'params': current_params.copy()
    }

    # 查找是否已有同 mode 的配置，若有则覆盖
    for idx, cfg in enumerate(saved_configs):
        if cfg.get('mode') == current_mode and cfg.get('color') == current_color:
            saved_configs[idx] = config_to_save
            print(f"[Main Process] 已覆盖 mode='{current_mode}' 的配置。")
            break
    else:
        # 未找到，则追加
        saved_configs.append(config_to_save)
        print(f"[Main Process] 新增 mode='{current_mode}' 的配置。")

    # 确保目录存在
    os.makedirs(os.path.dirname(CONFIGS_FILE), exist_ok=True)

    # 写回文件
    try:
        with open(CONFIGS_FILE, 'w') as f:
            json.dump(saved_configs, f, indent=2)
        print("[Main Process] 配置已保存到磁盘。")
    except Exception as e:
        print(f"[Main Process] Error saving configuration to file: {e}")


# 应用阈值到帧
def apply_threshold(frame, mode, params):
    if frame is None:
        return None
    processed_frame = frame.copy() # 处理副本
    try:
        if mode == 'hsv':
            if len(params) == 6: # 确保有所有 HSV 参数
                h_low, h_high, s_low, s_high, v_low, v_high = (
                    params.get('h_low', 0), params.get('h_high', 180),
                    params.get('s_low', 0), params.get('s_high', 255),
                    params.get('v_low', 0), params.get('v_high', 255)
                )
                # 转换为 HSV 颜色空间
                hsv_frame = cv2.cvtColor(processed_frame, cv2.COLOR_BGR2HSV)
                # 定义颜色阈值范围 (确保低阈值小于高阈值)
                lower_bound = np.array([min(h_low, h_high), min(s_low, s_high), min(v_low, v_high)])
                upper_bound = np.array([max(h_low, h_high), max(s_low, s_high), max(v_low, v_high)])
                # 创建掩膜，只保留在范围内的像素
                mask = cv2.inRange(hsv_frame, lower_bound, upper_bound)
                processed_frame = mask

                # 如果你的显示/保存函数要求输入三通道 BGR，可以再转回去：
                processed_frame = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
        elif mode == 'binary':
             thresh_value = params.get('thresh', -1)
             if 0 <= thresh_value <= 255: # 确保阈值有效
                 # 转换为灰度图
                 gray_frame = cv2.cvtColor(processed_frame, cv2.COLOR_BGR2GRAY)
                 # 应用二值化阈值
                 _, processed_frame = cv2.threshold(gray_frame, thresh_value, 255, cv2.THRESH_BINARY)
                 # 二值化图像是单通道的，为了显示需要转回三通道 (如果您的显示函数需要三通道)
                 processed_frame = cv2.cvtColor(processed_frame, cv2.COLOR_GRAY2BGR)
            
    except Exception as e:
        print(f"[Main Process] Error applying threshold ('{mode}' mode): {e}")
        # 发生错误时，可能返回原始帧或者一个错误提示画面
        return frame # 错误时返回原始帧

    return processed_frame


# --- UI 绘制函数 ---
def draw_ui(frame, screen_id, mode, params, clear_flag=0):
    """
    在帧上绘制当前画面的 UI 元素。
    frame: 要绘制的帧 (numpy array)。
    screen_id: 当前画面 ID。
    mode: 当前的模式 ('hsv', 'binary', None)。
    params: 当前模式的参数字典。
    clear_flag: 是否清除光标标签文字 (0/1)。
    """
    if frame is None or not isinstance(frame, np.ndarray):
        return frame  # 无效帧则不绘制

    screen_cfg = TOUCH_SCREENS.get(screen_id)
    if not screen_cfg:
        return frame  # 未知 screen_id

    h, w = frame.shape[:2]
    base_w, base_h = 1024, 600
    scale_x = w / base_w
    scale_y = h / base_h
    font_scale = (scale_x + scale_y) / 2

    # 要始终跳过文字绘制的滑条/阈值标签
    SLIDER_LABELS = {
        'h_low','h_high','s_low','s_high','v_low','v_high','thresh'
    }
    # clear_flag=1 时额外跳过的增/减按钮标签
    CLEAR_SKIP_LABELS = {
        'hl_d','hl_i','hh_d','hh_i',
        'sl_d','sl_i','sh_d','sh_i',
        'vl_d','vl_i','vh_d','vh_i',
        'thresh_d','thresh_i','red','two','blue','green','yellow','black','thresh_white'
    }
    
    for region_info in screen_cfg['regions']:
        label = region_info['label']
        x1, y1, x2, y2 = region_info['rect']
        # 缩放区域
        x1, y1 = int(x1 * scale_x), int(y1 * scale_y)
        x2, y2 = int(x2 * scale_x), int(y2 * scale_y)

        # 矩形颜色选择
        color = BUTTON_DRAW_CONFIG['default_color']
        if label in ('SAVE_HSV','SAVE_BIN'):
            color = BUTTON_DRAW_CONFIG['save_color'] if mode else BUTTON_DRAW_CONFIG['save_disabled_color']
        elif mode == 'hsv' and label == 'TO_HSV':
            color = BUTTON_DRAW_CONFIG['selected_color']
        elif mode == 'binary' and label == 'TO_BIN':
            color = BUTTON_DRAW_CONFIG['selected_color']
        # 文字起点
        text_x, text_y = x1 + 6, y1 + 35

        draw_text = True # 默认绘制文字
        draw_rectangle = True # 默认绘制矩形
        

        # 1) 滑条、阈值标签永不绘制文字
        if label in SLIDER_LABELS:
            draw_text = False

        # 2) clear_flag=1 时，跳过光标增/减标签
        if clear_flag == 1 and label in CLEAR_SKIP_LABELS:
            draw_text = False
        if label in CLEAR_SKIP_LABELS:
            text_x, text_y = x1 + 6, y1 + 20
        if clear_flag == 1 :
            draw_rectangle = False # 不绘制矩形
        if draw_rectangle:
            cv2.rectangle(frame, (x1, y1), (x2, y2), color, -1)

        # 如果需要，才绘制文字；否则跳过文字绘制，但继续后续逻辑
        if draw_text:
            cv2.putText(
                frame,
                label,
                (text_x, text_y),
                cv2.FONT_HERSHEY_SIMPLEX,
                font_scale,
                BUTTON_DRAW_CONFIG['text_color'],
                BUTTON_DRAW_CONFIG['font_thickness']
            )

    # 绘制滑条 (仅在模式激活且当前画面是调节画面时)
    if mode and (screen_id == 2 or screen_id == 3):
        sliders_config = TOUCH_SCREENS[screen_id].get('regions', []) # 获取当前画面的区域列表
        drag_sensitive_labels = set(TOUCH_SCREENS[screen_id].get('drag_sensitive_labels', [])) # 获取拖动敏感标签集合

        for region_info in sliders_config:
             label = region_info['label']
             if label in drag_sensitive_labels and clear_flag == 0: # 只绘制标记为滑条的区域
                rect = region_info['rect']
                x1, y1, x2, y2 = rect
                x1 = int (x1 * scale_x) # 缩放坐标
                y1 = int (y1 * scale_y)
                x2 = int (x2 * scale_x)
                y2 = int (y2 * scale_y)
                font_scale = 1 * ((scale_x + scale_y) / 2) 

                # 绘制滑条轨道 (一条横线)
                line_y = (y1 + y2) // 2
                cv2.line(frame, (x1, line_y), (x2, line_y), SLIDER_DRAW_CONFIG['line_color'], SLIDER_DRAW_CONFIG['line_thickness'])

                # 绘制滑块 (垂直短线)
                val = params.get(label, 0) # 获取当前滑条参数值
                # 确定滑条的最大值
                maxv = 255 # 默认最大值
                if mode == 'hsv':
                    if label.startswith('h_'): maxv = 180
                    elif label.startswith('s_'): maxv = 255
                    elif label.startswith('v_'): maxv = 255
                # else: mode is 'binary', label is 'thresh', maxv is 255
                maxv = max(1, maxv) # 确保最大值至少为 1

                # 计算滑块的 x 坐标，限制在滑条轨道范围内
                clamped_val = max(0, min(val, maxv))
                bx = int(x1 + (clamped_val / maxv) * (x2 - x1))

                # 绘制一个小的垂直矩形作为滑块
                slider_bar_height = (y2 - y1) + SLIDER_DRAW_CONFIG['slider_bar_height_offset']
                cv2.rectangle(frame,
                              (bx - SLIDER_DRAW_CONFIG['slider_bar_width'] // 2, y1 - (slider_bar_height - (y2 - y1)) // 2), # 左上角
                              (bx + (SLIDER_DRAW_CONFIG['slider_bar_width'] + 1) // 2, y2 + (slider_bar_height - (y2 - y1)) // 2), # 右下角
                              SLIDER_DRAW_CONFIG['slider_bar_color'], -1) # 红色滑块

                # 绘制滑条标签和值
                text_label = f"{label}:{val}"
                cv2.putText(frame, text_label, (x1+SLIDER_DRAW_CONFIG['label_offset_x'], y1 + SLIDER_DRAW_CONFIG['label_offset_y']), cv2.FONT_HERSHEY_SIMPLEX,
                           font_scale, SLIDER_DRAW_CONFIG['text_color'], SLIDER_DRAW_CONFIG['font_thickness'])


    return frame

# --- 主进程逻辑 ---
def main_process():

    print("[主进程] 应用程序正在启动...")
    processes = []

    # 准备进程创建所需的信息 
    video1_args = (RUNNING_FLAG, ENABLE_FRAME_1,frame1_queue,'cap_main',{'width': 640, 'height': 480, 'fps': 30})

    touch_args = (RUNNING_FLAG, ENABLE_TOUCH_SCREEN,touch_data_queue)

    # 1. 发现摄像头设备
    p_video1_frame = multiprocessing.Process(target=camera_reader_process,
                                            args=video1_args,
                                            daemon=True)
    # 存储进程信息，
    processes.append({"name": "video1_frame", "process": p_video1_frame, "target": camera_reader_process, "args": video1_args})
    p_video1_frame.start()


    # 2. 启动触摸屏控制进程
    p_touch_screen = multiprocessing.Process(target=hdmi_touch_task,
                                            args=touch_args,
                                            daemon=True)
    # 存储进程信息
    processes.append({"name": "TouchScreen", "process": p_touch_screen, "target": hdmi_touch_task, "args": touch_args})
    p_touch_screen.start()

   # 初始化 HDMI 显示器
    try:
        hdmi_display_img = HDMI_Display()

        print("[HDMI 显示进程] HDMI_Display 初始化成功。")
    except Exception as e:
        print(f"[HDMI 显示进程] HDMI_Display 初始化失败: {e}")

    global current_screen_id, current_mode, current_color,current_params, saved_configs

    # 初始化画面 ID (例如，从画面 1 开始)
    current_screen_id = 1
    ENABLE_TOUCH_SCREEN.value = current_screen_id # 通知触摸进程当前画面

    # 加载已保存的配置
    load_configs()
    clear_flag = 0 # 清除标志，初始为 0

    frame = None # 存储从摄像头队列获取的帧
    adjust_flag = 0
    start_adjust = 0
    last_color = None

    try:
        # 主循环
        while RUNNING_FLAG.is_set():
            try:
                _, frame = frame1_queue.get(timeout=0.005) # 短暂超时
                start_adjust =  1
                if frame is None:
                    continue # 跳过空的帧
            except queue.Empty:
                if frame is None: # 如果还没有获取到第一帧
                    frame = 255 * np.ones((600, 1024, 3), dtype=np.uint8) 
            except Exception as e:
                print(f"[Main Process] Error getting frame from queue: {e}")
                if frame is None: # 读取失败且没有旧帧，创建黑色背景
                    frame = 255*np.ones((600, 1024, 3), dtype=np.uint8)
                pass #
            try:
                touch_data = touch_data_queue.get(timeout=0.01) 
                adjust_flag = 0 # 重置微调标志
            except queue.Empty:
                
                touch_data = None
            
            if touch_data and touch_data[0] == current_screen_id:
                # 解析触摸数据
                screen_id, region_index, region_rect, region_label, touch_x, touch_y = touch_data
                if region_label == 'TO_HSV':
                    if current_screen_id != 2: # 避免重复切换
                        print("[Main Process] Switching to HSV adjust screen.")
                        current_screen_id = 2
                        current_mode = 'hsv'
                        current_params = {k: (90 if k.startswith('h_') else 128) for k in TOUCH_SCREENS[2]['regions'] if k in TOUCH_SCREENS[2]['drag_sensitive_labels']}
                        ENABLE_TOUCH_SCREEN.value = current_screen_id # 通知触摸进程

                elif region_label == 'TO_BIN':
                    if current_screen_id != 3: 
                        print("[Main Process] Switching to BINARY adjust screen.")
                        current_screen_id = 3
                        current_mode = 'binary'
                        # 初始化 BINARY 参数
                        current_params = {'thresh': 128}
                        ENABLE_TOUCH_SCREEN.value = current_screen_id # 通知触摸进程

                elif region_label == 'TO_MAIN':
                    if current_screen_id != 1: # 避免重复切换
                        print("[Main Process] Switching back to Main screen.")
                        current_screen_id = 1
                        ENABLE_TOUCH_SCREEN.value = current_screen_id # 通知触摸进程
                        clear_flag = 0

                elif region_label == 'RESET': # 示例：主界面重置按钮
                    if current_screen_id == 1:
                        print("[Main Process] Resetting current mode and parameters.")
                        current_mode = None
                        RUNNING_FLAG.clear()
                        restart_program()
                elif region_label == 'ESC': # 示例：主界面退出按钮
                    if current_screen_id == 1:
                        print("[Main Process] Exit button pressed, setting run_flag to False.")
                        RUNNING_FLAG.clear() # 设置事件为 False，通知其他进程退出

                # 检查是否是保存按钮
                elif region_label.startswith('SAVE_'):
                    if current_mode and (
                        (current_mode == 'hsv' and region_label == 'SAVE_HSV') or
                        (current_mode == 'binary' and region_label == 'SAVE_BIN')
                    ):
                        print(f"[Main Process] Save button '{region_label}' pressed.")
                        save_current_config()
                    else:
                        print(f"[Main Process] Save button '{region_label}' pressed, but no active mode to save.")

            elif current_mode and (current_screen_id == 2 or current_screen_id == 3): 
                #  先根据触摸区域判断当前是哪种颜色
                if 'red' in region_label:
                    current_color = 'red'
                elif 'two' in region_label:  # 注意这里是 'two' 而不是 'red2'
                    current_color = 'redtwo'  # 保持与原代码一致
                elif 'blue' in region_label:
                    current_color = 'blue'
                elif 'green' in region_label:
                    current_color = 'green'
                elif 'yellow' in region_label:
                    current_color = 'yellow'
                elif 'black' in region_label:
                    current_color = 'black'
                elif 'thresh_white' in region_label:
                    current_color = 'thresh_white'

                # 2) 只要颜色一变，就重新从 saved_configs 加载，找不到就全 0
                if current_color != last_color:
                    # 默认一个空字典
                    new_params = None
                    for cfg in saved_configs:
                        if cfg.get('mode') == current_mode:
                            if current_mode == 'hsv' and cfg.get('color') == current_color:
                                new_params = cfg['params'].copy()
                                break
                            elif current_mode == 'binary':
                                new_params = cfg['params'].copy()
                                break

                    if new_params is None:
                        # 没有对应存储，就构造全 0 的默认
                        if current_mode == 'binary':
                            new_params = {'thresh': 0}
                        else:
                            new_params = {
                                'h_low':  0, 'h_high': 0,
                                's_low':  0, 's_high': 0,
                                'v_low':  0, 'v_high': 0
                            }
                    # 更新当前参数
                    current_params.clear()
                    current_params.update(new_params)
                    last_color = current_color

                # 拖拽滑条
                sliders_config = TOUCH_SCREENS[current_screen_id].get('regions', [])
                drag_sensitive_labels = set(TOUCH_SCREENS[current_screen_id].get('drag_sensitive_labels', []))
                adjust_map = {
                    'hl_d': ('h_low',  -1),  'hl_i': ('h_low',  +1),
                    'hh_d': ('h_high', -1),  'hh_i': ('h_high', +1),
                    'sl_d': ('s_low',  -1),  'sl_i': ('s_low',  +1),
                    'sh_d': ('s_high', -1),  'sh_i': ('s_high', +1),
                    'vl_d': ('v_low',  -1),  'vl_i': ('v_low',  +1),
                    'vh_d': ('v_high', -1),  'vh_i': ('v_high', +1),
                    'thresh_d': ('thresh', -1), 'thresh_i': ('thresh', +1)
                }
                if region_label in adjust_map and adjust_flag == 0:

                    param_name, delta = adjust_map[region_label]
                    current_params.setdefault(param_name, 0)
                    if current_mode == 'hsv':
                        if param_name.startswith('h_'):
                            maxv = 180
                        else:
                            maxv = 255
                    else:  # binary 下只有 thresh
                        maxv = 255
                        
                    # 增减并限幅
                    new_v = current_params[param_name] + delta
                    new_v = max(0, min(maxv, new_v))
                    current_params[param_name] = new_v
                    adjust_flag = 1 

                # 再处理滑条拖拽
                if region_label in drag_sensitive_labels:
                    x1, y1, x2, y2 = region_rect
                    range_width = x2 - x1
                    if range_width > 0:
                        clamped_touch_x = max(x1, min(touch_x, x2))
                        pct = (clamped_touch_x - x1) / range_width
                        pct = max(0.0, min(1.0, pct))
                        # 选择 maxv 同上
                        if current_mode == 'hsv':
                            if region_label.startswith('h_'): maxv = 180
                            else:                              maxv = 255
                        else:
                            maxv = 255
                        maxv = max(1, maxv)
                        current_params[region_label] = int(pct * maxv)

                # clear / recover 按钮
                if 'CLE' in region_label:
                    clear_flag = 1
                if 'REC' in region_label:
                    clear_flag = 0

            # 3. 应用阈值处理 
            if frame is not None and (current_screen_id == 2 or current_screen_id == 3) and current_mode and current_params:
                frame_to_display = apply_threshold(frame, current_mode, current_params)
            else:
                frame_to_display = frame # 主界面或无模式时不应用阈值

            # 4. 在帧上绘制 UI 元素
            if frame_to_display is not None and isinstance(frame_to_display, np.ndarray):
                if current_screen_id == 1:
                    frame_to_display = 255*np.ones((600, 1024, 3), dtype=np.uint8)
                final_frame = draw_ui(frame_to_display, current_screen_id, current_mode, current_params,clear_flag)
            else:
                black_frame = 255*np.ones((600, 1024, 3), dtype=np.uint8)
                final_frame = draw_ui(black_frame, current_screen_id, current_mode, current_params,clear_flag)

            # 5. 显示帧
            if final_frame is not None and isinstance(final_frame, np.ndarray) and  start_adjust == 1:
                hdmi_display_img.display_frame(final_frame)
            else:
                # print("[Main Process] Final frame is None or invalid, cannot display.")
                pass 


    except KeyboardInterrupt:
        print("[主进程] 收到KeyboardInterrupt。正在关闭...")
    except Exception as e:
         print(f"[主进程] 主循环发生未捕获异常: {e}")
    finally:
        print("[主进程] 正在启动关闭序列...")
        RUNNING_FLAG.clear() # 通知所有子进程停止

        # 给子进程一点时间响应停止标志
        time.sleep(0.1) # 短暂等待

        # 遍历并尝试终止所有进程
        for p_info in processes:
            p = p_info['process']
            pname = p_info['name']
            if p.is_alive():
                 print(f"[主进程] 正在发送终止信号给 {pname} 进程...")
                 try:
                    p.terminate()
                 except Exception as e:
                    print(f"[主进程] 发送终止信号给 {pname} 时出错: {e}")


        # 再次遍历，等待所有进程退出
        for p_info in processes:
            p = p_info['process']
            pname = p_info['name']
            if p.is_alive():
                print(f"[主进程] 等待 {pname} 进程退出...")
                try:
                    p.join(timeout=2) # 等待更长时间
                    if p.is_alive():
                        print(f"[主进程] {pname} 进程未正常退出，可能需要手动检查。")
                except Exception as e:
                    print(f"[主进程] 等待 {pname} 退出时出错: {e}")
            else:
                print(f"[主进程] {pname} 进程已退出。")


        # Close queues
        print("[主进程] 正在关闭队列...")
        queues_to_close = [
            frame1_queue,touch_data_queue
        ]

        for q_obj in queues_to_close:
            try:
                q_obj.close()
           
                try:
                    q_obj.join_thread()
                except RuntimeError:
                     # join_thread might raise RuntimeError if the thread wasn't started or already joined
                     pass
                print(f"[主进程] 队列已关闭: {q_obj}")
            except Exception as e_q:
                print(f"[主进程] 关闭队列 {q_obj} 时出错: {e_q}")

        cv2.destroyAllWindows()
        print("[主进程] 应用程序已关闭。")



if __name__ == "__main__":
    multiprocessing.freeze_support()
    main_process()